package lzw.codec.managers;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

import lzw.codec.exceptions.SystemException;

/**
 * This class is an implementation of LZWFileManager.
 * 
 * @see lzw.codec.managers.LZWCodecManager
 * 
 * @author Bruno Cartaxo
 * @author Antônio Correia
 * 
 * @since SEP 2009
 * 
 */
public class LZWFileManagerImpl extends LZWFileManager {

	/**
	 * The singleton shared instance
	 */
	private static LZWFileManagerImpl instance = new LZWFileManagerImpl();
	private FileReader reader;
	private BufferedReader buffer;
	private FileWriter writer;

	/**
	 * The hidden constructor.
	 */
	private LZWFileManagerImpl(){
		// Empty constructor
	}

	/**
	 * The method to return the shared singleton instance.
	 * @return The shared singleton instance.
	 */
	public synchronized static LZWFileManager getInsntace() {
		return instance;
	}

	/**
	 * @see LZWFileManager#loadInitialEncoderDictionary(String)
	 * 
	 * @author Antônio Correia
	 */
	public Map<Integer, String> loadInitialEncoderDictionary(String filePath) {
		String line = null;
		Map<Integer, String> toReturn = new HashMap<Integer, String>();

		try {
			reader = new FileReader(new File(filePath));
			buffer = new BufferedReader(reader);
		} catch (FileNotFoundException e) {
			throw new SystemException("The encoder dictionary is not found.", e);
		}

		do{

			try {
				line = buffer.readLine();
			} catch (IOException e) {
				throw new SystemException("The File could not be readed.", e);
			}

			if(line != null){

				String[] parts = line.split("#");
				Integer key;
				try {
					key = Integer.parseInt(parts[0]);
				} catch (NumberFormatException e) {
					throw new SystemException("Arquivo com formato inválido.", e);
				}
				String value = parts[1];

				toReturn.put(key, value);
			}
		}while(line != null);

		return toReturn;
	}

	/**
	 * @see LZWFileManager#loadInitialDecoderDictionary(String)
	 * 
	 * @author Antônio Correia
	 */
	public Map<Integer, String> loadInitialDecoderDictionary(String filePath) {
		String line = null;
		Map<Integer, String> toReturn = new HashMap<Integer, String>();

		try {
			reader = new FileReader(new File(filePath));
			buffer = new BufferedReader(reader);
		} catch (FileNotFoundException e) {
			throw new SystemException("The decoder dictionary is not found.", e);
		}

		do{

			try {
				line = buffer.readLine();
			} catch (IOException e) {
				throw new SystemException("The File could not be readed.", e);
			}

			if(line != null){

				String[] parts = line.split("#");
				Integer key;
				try {
					key = Integer.parseInt(parts[0]);
				} catch (NumberFormatException e) {
					throw new SystemException("Arquivo com formato inválido.", e);
				}
				String value = parts[1];

				toReturn.put(key, value);
			}


		}while(line != null);

		return toReturn;
	}

	/**
	 * @see LZWFileManager#loadSourceFile(String)
	 * 
	 * @author Antônio Correia
	 */
	public String loadSourceFile(String filePath) {
		String toReturn = null;
		try {
			reader = new FileReader(new File(filePath));
			buffer = new BufferedReader(reader);
		} catch (FileNotFoundException e) {
			throw new SystemException("The source file is not found!", e);
		}

		try {
			toReturn = buffer.readLine();
		} catch (IOException e) {
			throw new SystemException("The File could not be readed.", e);
		}

		return toReturn;
	}
	
	/**
	 * @see LZWFileManager#loadEncodedFile(String)
	 * 
	 * @author Antônio Correia
	 */
	public String loadEncodedFile(String filePath) {
		String toReturn = null;
		try {
			reader = new FileReader(new File(filePath));
			buffer = new BufferedReader(reader);
		} catch (FileNotFoundException e) {
			throw new SystemException("The encoded file is not found.", e);
		}

		try {
			toReturn = buffer.readLine();
		} catch (IOException e) {
			throw new SystemException("The File could not be readed.", e);
		}

		return toReturn;
	}

	/**
	 * @see LZWFileManager#generateEncodedFile(String, String)
	 * 
	 * @author Antônio Correia
	 */
	public void generateEncodedFile(String filePath, String encoded) {
		try {
			File file = new File(filePath);
			file.createNewFile();
			writer = new FileWriter(file);

			writer.write(encoded);
			writer.flush();
			writer.close();
		} catch (IOException e) {
			throw new SystemException("Erro ao tentar criar o arquivo codificado.", e);
		}
	}

	/**
     * @see LZWFileManager#generateFileSequence(java.lang.String, java.lang.String)
     * 
	 * @author GutembergRCC
	 */
	public void generateFileSequence(String sequence, String filePath){
		try {
		File file = new File(filePath);
        file.createNewFile();
        PrintWriter writer = new PrintWriter(new FileWriter(file));
        writer.print(sequence);
        writer.close();
		} catch (IOException e) {
			throw new SystemException("Erro ao tentar criar o arquivo de sequência.", e);
		}
        
    }
	
}
